package cn.edu.zut.sunday.blimp.controller;

import cn.edu.zut.sunday.base.controller.GenericController;
import cn.edu.zut.sunday.blimp.domain.DatasetName;
import cn.edu.zut.sunday.blimp.domain.constant.TableHeader;
import cn.edu.zut.sunday.blimp.func.DatasetNameTransformUtils;
import cn.edu.zut.sunday.blimp.service.DatasetNameService;
import cn.edu.zut.sunday.blimp.vo.DatasetInfoQuery;
import cn.edu.zut.sunday.blimp.vo.DatasetNameVo;
import cn.edu.zut.sunday.blimp.vo.Options;
import cn.edu.zut.sunday.utils.MD5Utils;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Lists;
import com.google.gson.Gson;
import com.google.gson.JsonSyntaxException;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import javax.persistence.criteria.Predicate;
import javax.servlet.http.HttpServletRequest;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@Slf4j
@Api("blimp-数据集信息表接口")
@RestController
@RequestMapping("/blimp/dataset")
public class DatasetNameController extends
  GenericController<DatasetName, Integer, DatasetNameService> {


    /**
     * 创建datasetNameServiceImpl对象
     *
     * @param datasetNameServiceImpl 由IOC自动注入服务对象
     */
    @Autowired
    public void setDatasetNameServiceImpl(DatasetNameService datasetNameServiceImpl) {
        this.service = datasetNameServiceImpl;
    }

    /**
     * 返回所有dataset的id和name组成的映射表。比如
     *  id2NameMap(id -> datasetName)： 1->dataset1, 2->dataset2....；
     *  name2IdMap(datasetName -> id)： dataset1->1, dataset2->2....；
     *
     * @return 一个Map，有两个Key：id2NameMap和name2IdMap
     */
    @ApiOperation(value = "返回ID和Name的对应表信息")
    @GetMapping("/idList")
    public List<Options> idList() {
        final List<DatasetName> datasetNameList = this.service.findAll();

        return datasetNameList.stream()
          .map(v -> new Options(String.valueOf(v.getId()), v.getSetName()))
          .collect(Collectors.toList());
    }

    /**
     * 针对前端插入一个新的对象数据执行检查操作
     *
     * @param model 前端数据对象
     * @return 返回检查后的model对象
     */
    @Override
    protected DatasetName addModelCheck(DatasetName model,
      HttpServletRequest request) {

        final String setName   = model.getSetName();
        final long   dataCount = model.getDataCount();
        if (StringUtils.isEmpty(setName) || dataCount < 0) {
            return null;
        }
        model.setMd5(MD5Utils.getMD5(setName));

        return model;
    }

    /**
     * 针对前端更新一个新的对象数据执行检查操作
     *
     * @param id 需要修改的实体id信息
     * @param model 前端数据对象
     * @return 返回检查后的model对象
     */
    @Override
    protected DatasetName updateModelCheck(Integer id, DatasetName model,
      HttpServletRequest request) {
        if (id <= 0) {return null;}
        model.setId(id);
        return addModelCheck(model, request);
    }

    /**
     * 对前端传送的高级搜索进行配置，主要是根据（setName，md5，dataCreated）属性进行高级搜索
     *
     * @param requestBodyStr 请求的RequestBody字符串对象，需要之类使用序列化工具创建对应对象
     * @return Specification对象
     */
    @Override
    protected Specification<DatasetName> createSpecification(String requestBodyStr) {
        try {
            final DatasetInfoQuery infoQuery = new Gson().fromJson(requestBodyStr,
              DatasetInfoQuery.class);
            final ArrayList<Predicate> list = Lists.newArrayList();

            return (root, query, cb) -> {
                if (StringUtils.isNotEmpty(infoQuery.getSetName())) {
                    list.add(cb.like(root.get("setName"), sqlLike(infoQuery.getSetName())));
                }
                if (StringUtils.isNotEmpty(infoQuery.getMd5())) {
                    list.add(cb.like(root.get("md5"), sqlLike(infoQuery.getMd5())));
                }
                return cb.and(list.toArray(new Predicate[0]));
            };
        } catch (JsonSyntaxException e) {
            log.error("反序列化对象失败: {}", requestBodyStr);
        }
        return null;
    }

    /**
     * 该方法是对从数据库中查询出来的分页数据进行VO封装
     *
     * @param resultPage 从数据库中获取的数据库实体信息
     * @return 封装了表头和分页信息的Map对象
     */
    @Override
    protected Object transform(Page<DatasetName> resultPage) {
        final Page<DatasetNameVo> datasetNameVoPage = resultPage.map(
          DatasetNameTransformUtils.ENTITY_2_VO);
        final HashMap<String, Object> map = new HashMap<>();
        map.put("page", datasetNameVoPage);
        map.put("header", TableHeader.DATASET_NAME.getHeader());
        return map;
    }

    /**
     * 该方法对从数据库中查出来的实体进行VO封装
     *
     * @param entity 从数据库中获取的一个数据库实体信息
     * @return 封装后的数据对象
     */
    @Override
    protected Object transform(DatasetName entity) {
        return DatasetNameTransformUtils.ENTITY_2_VO.apply(entity);
    }
}
